package cn.yunbamboos.media.dispatcher;

import cn.yunbamboos.media.hook.MediaHookService;
import cn.yunbamboos.media.hook.in.GenericHookInDTO;
import cn.yunbamboos.media.hook.in.ServerExitedHookInDTO;
import cn.yunbamboos.media.hook.in.ServerKeepaliveHookInDTO;
import cn.yunbamboos.media.hook.in.ServerStartedHookInDTO;
import cn.yunbamboos.media.hook.in.StreamNotFoundHookInDTO;
import cn.yunbamboos.media.hook.out.IHookOutDTO;
import jakarta.annotation.Resource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class ZLMediaKitHookServiceDispatcher {

    private static final Logger logger = LoggerFactory.getLogger(ZLMediaKitHookServiceDispatcher.class);

    @Resource
    private MediaHookService mediaHookService;

    /**
     * 解释：
     * 流量统计事件，播放器或推流器断开时并且耗用流量超过特定阈值时会触发此事件，阈值通过配置文件general.flowThreshold配置；此事件对回复不敏感。
     */
    @RequestMapping({"${yunbamboos.media.hook-path}/on_flow_report"})
    public String onFlowReport(@RequestBody String body) {
        logger.debug("on_flow_report body: {}", body);
        IHookOutDTO out = mediaHookService.onFlowReport(new GenericHookInDTO(body));
        String result = out.toJSONString();
        logger.debug("on_flow_report result: {}", result);
        return result;
    }

    /**
     * 访问http文件服务器上hls之外的文件时触发。
     * */
    @RequestMapping({"${yunbamboos.media.hook-path}/on_http_access"})
    public String onHttpAccess(@RequestBody String body) {
        logger.debug("on_http_access: {}", body);
        IHookOutDTO out = mediaHookService.onHttpAccess(new GenericHookInDTO(body));
        String result = out.toJSONString();
        logger.debug("on_http_access result: {}", result);
        return result;
    }

    /**
     * 播放器鉴权事件，rtsp/rtmp/http-flv/ws-flv/hls的播放都将触发此鉴权事件；
     *  如果流不存在，那么先触发on_play事件然后触发on_stream_not_found事件。
     *  播放rtsp流时，如果该流启动了rtsp专属鉴权(on_rtsp_realm)那么将不再触发on_play事件。
     * */
    @RequestMapping({"${yunbamboos.media.hook-path}/on_play"})
    public String onPlay(@RequestBody String body) {
        logger.debug("on_play: {}", body);
        IHookOutDTO out = mediaHookService.onPlay(new GenericHookInDTO(body));
        String result = out.toJSONString();
        logger.debug("on_play result: {}", result);
        return result;
    }

    /**
     * rtsp/rtmp/rtp推流鉴权事件。
     * */
    @RequestMapping({"${yunbamboos.media.hook-path}/on_publish"})
    public String onPublish(@RequestBody String body) {
        logger.debug("on_publish: {}", body);
        IHookOutDTO out = mediaHookService.onPublish(new GenericHookInDTO(body));
        String result = out.toJSONString();
        logger.debug("on_publish result: {}", result);
        return result;
    }

    /**
     * 录制mp4完成后通知事件；此事件对回复不敏感。
     * */
    @RequestMapping({"${yunbamboos.media.hook-path}/on_record_mp4"})
    public String onRecordMp4(@RequestBody String body) {
        logger.debug("on_record_mp4: {}", body);
        IHookOutDTO out = mediaHookService.onRecordMp4(new GenericHookInDTO(body));
        String result = out.toJSONString();
        logger.debug("on_record_mp4 result: {}", result);
        return result;
    }

    /**
     * rtsp专用的鉴权事件，先触发on_rtsp_realm事件然后才会触发on_rtsp_auth事件。
     * */
    @RequestMapping({"${yunbamboos.media.hook-path}/on_rtsp_auth"})
    public String onRtspAuth(@RequestBody String body) {
        logger.debug("on_rtsp_auth: {}", body);
        IHookOutDTO out = mediaHookService.onRtspAuth(new GenericHookInDTO(body));
        String result = out.toJSONString();
        logger.debug("on_rtsp_auth result: {}", result);
        return result;
    }

    /**
     * 该rtsp流是否开启rtsp专用方式的鉴权事件，开启后才会触发on_rtsp_auth事件。
     * 需要指出的是rtsp也支持url参数鉴权，它支持两种方式鉴权。
     * */
    @RequestMapping({"${yunbamboos.media.hook-path}/on_rtsp_realm"})
    public String onRtspRealm(@RequestBody String body) {
        logger.debug("on_rtsp_realm: {}", body);
        IHookOutDTO out = mediaHookService.onRtspRealm(new GenericHookInDTO(body));
        String result = out.toJSONString();
        logger.debug("on_rtsp_realm result: {}", result);
        return result;
    }

    /**
     * shell登录鉴权，ZLMediaKit提供简单的telnet调试方式
     * 使用telnet 127.0.0.1 9000能进入MediaServer进程的shell界面。
     * */
    @RequestMapping({"${yunbamboos.media.hook-path}/on_shell_login"})
    public String onShellLogin(@RequestBody String body) {
        logger.debug("on_shell_login: {}", body);
        IHookOutDTO out = mediaHookService.onShellLogin(new GenericHookInDTO(body));
        String result = out.toJSONString();
        logger.debug("on_shell_login result: {}", result);
        return result;
    }

    /**
     * rtsp/rtmp流注册或注销时触发此事件；此事件对回复不敏感。
     * */
    @RequestMapping({"${yunbamboos.media.hook-path}/on_stream_changed"})
    public String onStreamChanged(@RequestBody String body) {
        logger.debug("on_stream_changed: {}", body);
        IHookOutDTO out = mediaHookService.onStreamChanged(new GenericHookInDTO(body));
        String result = out.toJSONString();
        logger.debug("on_stream_changed result: {}", result);
        return result;
    }

    /**
     * 流无人观看时事件，用户可以通过此事件选择是否关闭无人看的流。
     *  一个直播流注册上线了，如果一直没人观看也会触发一次无人观看事件，触发时的协议schema是随机的，看哪种协议最晚注册(一般为hls)。
     *  后续从有人观看转为无人观看，触发协议schema为最后一名观看者使用何种协议。
     *  目前mp4/hls录制不当做观看人数(mp4录制可以通过配置文件mp4_as_player控制，但是rtsp/rtmp/rtp转推算观看人数，也会触发该事件。
     * */
    @RequestMapping({"${yunbamboos.media.hook-path}/on_stream_none_reader"})
    public String onStreamNoneReader(@RequestBody String body) {
        logger.debug("on_stream_none_reader: {}", body);
        IHookOutDTO out = mediaHookService.onStreamNoneReader(new GenericHookInDTO(body));
        String result = out.toJSONString();
        logger.debug("on_stream_none_reader result: {}", result);
        return result;
    }

    /**
     * 流未找到事件，用户可以在此事件触发时，立即去拉流，这样可以实现按需拉流；此事件对回复不敏感。
     * */
    @RequestMapping({"${yunbamboos.media.hook-path}/on_stream_not_found"})
    public String onStreamNotFound(@RequestBody String body) {
        logger.debug("on_stream_not_found: {}", body);
        IHookOutDTO out = mediaHookService.onStreamNotFound(new StreamNotFoundHookInDTO(body));
        String result = out.toJSONString();
        logger.debug("on_stream_not_found result: {}", result);
        return result;
    }


    @RequestMapping({"${yunbamboos.media.hook-path}/on_rtp_server_timeout"})
    public String onRtpServerTimeout(@RequestBody String body) {
        logger.debug("on_rtp_server_timeout: {}", body);
        IHookOutDTO out = mediaHookService.onRtpServerTimeout(new GenericHookInDTO(body));
        String result = out.toJSONString();
        logger.debug("on_rtp_server_timeout result: {}", result);
        return result;
    }

    /**
     * 服务器启动事件，可以用于监听服务器崩溃重启；此事件对回复不敏感。
     * */
    @RequestMapping({"${yunbamboos.media.hook-path}/on_server_started"})
    public String onServerStarted(@RequestBody String body) {
        logger.debug("on_server_started: {}", body);
        IHookOutDTO out = mediaHookService.onServerStarted(new ServerStartedHookInDTO(body));
        String result = out.toJSONString();
        logger.debug("on_server_started result: {}", result);
        return result;
    }

    @RequestMapping({"${yunbamboos.media.hook-path}/on_server_exited"})
    public String onServerExited(@RequestBody String body) {
        logger.debug("on_server_exited: {}", body);
        IHookOutDTO out = mediaHookService.onServerExited(new ServerExitedHookInDTO(body));
        String result = out.toJSONString();
        logger.debug("on_server_exited result: {}", result);
        return result;
    }

    /**
     * 服务器定时上报时间，上报间隔可配置，默认10s上报一次
     * */
    @RequestMapping({"${yunbamboos.media.hook-path}/on_server_keepalive"})
    public String onServerKeepalive(@RequestBody String body) {
        logger.debug("on_server_keepalive: {}", body);
        IHookOutDTO out = mediaHookService.onServerKeepalive(new ServerKeepaliveHookInDTO(body));
        String result = out.toJSONString();
        logger.debug("on_server_keepalive result: {}", result);
        return result;
    }

}
